// 导入其它类
import Food from "./Food";
import ScorePanel from "./ScorePanel";
import Snake from "./Snake";

// 游戏控制类
class GameControl {
  // 定义三个属性 代表三个类
  snake: Snake;
  food: Food;
  scorePanel: ScorePanel;

  // 存储蛇的按键方向
  direction: string = "";

  // 记录游戏是否结束
  isLive: boolean = true;

  // 构造函数
  constructor() {
    this.snake = new Snake();
    this.food = new Food();
    this.scorePanel = new ScorePanel(10, 2);
    // 初始化游戏
    this.init();
  }

  // 定义游戏初始化方法
  init() {
    // 绑定键盘事件
    // TODO: 这个有个bind方法去修改了keydownHandler的this指向
    document.addEventListener("keydown", this.keydownHandler.bind(this));
    // 更新食物位置
    this.food.change();
    // 调用run方法让蛇移动
    this.run();
  }

  // 键盘事件响应函数
  keydownHandler(event: KeyboardEvent) {
    // 我们只处理 w: 上 s: 下 a: 左 d:右
    // 限制方向键
    // console.log(event.key);
    if (
      event.key == "w" ||
      event.key == "s" ||
      event.key == "a" ||
      event.key == "d" ||
      event.key == "ArrowUp" ||
      event.key == "ArrowDown" ||
      event.key == "ArrowLeft" ||
      event.key == "ArrowRight"
    ) {
      this.direction = event.key;
    }
  }

  // 创建一个控制蛇移动的方法
  run() {
    // 1.获取蛇现在的坐标位置
    let X = this.snake.X;
    let Y = this.snake.Y;
    // 2.根据 direction 判断位置
    // 向上: top-10
    // 向下: top+10
    // 向左: left-10
    // 向右: left+10
    switch (this.direction) {
      case "w":
      case "ArrowUp":
        Y -= 10;
        break;
      case "s":
      case "ArrowDown":
        Y += 10;
        break;
      case "a":
      case "ArrowLeft":
        X -= 10;
        break;
      case "d":
      case "ArrowRight":
        X += 10;
        break;
    }

    // 检查是否吃到食物
    this.checkEat(X, Y);

    // 捕获异常
    try {
      // 移动身体: 在头部元素移动之前赋值 否则第二个元素更第一个元素坐标会保持一个
      // 以至于用户看不见第二个元素
      // this.snake.moveBody();
      this.snake.X = X;
      this.snake.Y = Y;
    } catch (e) {
      // 进入到了catch代表游戏结束 弹出消息告诉用户
      // 终止游戏
      this.isLive = false;
      alert(e.message);
    }
    // 每隔300毫秒调用一下自身 递归调用 速度根据等级计算
    // 1: 300 - (1 - 1) * 30 = 300
    // 2: 300 - (2 - 1) * 30 = 270
    // ......
    // 10: 300 - (10 - 1) * 30 = 30
    this.isLive && setTimeout(this.run.bind(this), 300 - (this.scorePanel.level - 1) * 30);
  }

  // 检查蛇是否吃到了食物
  checkEat(X: number, Y: number) {
    // 蛇的坐标与食物坐标重合则为迟到了
    if (X === this.food.X && Y === this.food.Y) {
      console.log("吃到食物啦");
      // 1.食物位置重置
      this.food.change();
      // 2.分数增加
      this.scorePanel.addScore();
      // 3.蛇增加一个身体
      this.snake.addBody();
    }
  }
}

export default GameControl;